﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading;
using RegexParser;

namespace RegexParserTest
{
	class Program
	{
		private static Dictionary<string, int> CategoryCounts;
		private static Random random = new Random(DateTime.Now.Millisecond);
		private const string LegalCharacters = @"01pkbwsnrtx[](){}\+*?<>:|^$.=!#-,";

		private static string RandomString(int size)
		{
			var RandomStringBuilder = new StringBuilder(size);
			char ch;
			
			for (int i = 0; i < size; i++)
			{
				ch = LegalCharacters[random.Next(0, LegalCharacters.Length)];
				RandomStringBuilder.Append(ch);
			}

			return RandomStringBuilder.ToString();
		}

		private static void TestSpeedAndAccuracy(long iterations)
		{
			var rp = new RegexParser.Parser();
			var sw = new Stopwatch();

			int FailedCount = 0;

			Console.WriteLine("Testing speed and accuracy with " + iterations.ToString() + " random regular expressions...");

			sw.Start();
			for (long i = 0; i < iterations; i++)
			{
				string Pattern = RandomString(random.Next(3, 10));
				rp.Run(Pattern);

				var sbPattern = new StringBuilder(Pattern.Length);
				foreach (var Token in rp.FlattenedTokens)
				{
					sbPattern.Append(Token.Pattern);
				}

				// Display any pattern that doesn't match the original
				if (Pattern != sbPattern.ToString())
				{
					FailedCount++;
					Console.Write(Pattern);
					Console.Write('\t');
					Console.Write(sbPattern.ToString());
					Console.WriteLine();
				}
			}
			sw.Stop();

			Console.WriteLine("DONE");
			Console.WriteLine(FailedCount.ToString() + " failures");
			Console.WriteLine(sw.ElapsedMilliseconds + " ms");
			Console.WriteLine();
		}


		static void Main(string[] args)
		{
			TestSpeedAndAccuracy(5000000);

			var rp = new RegexParser.Parser();

			string line;
			Console.WriteLine("Enter a regular expression and press enter (press CTRL+Z to exit):");
			Console.WriteLine();
			do
			{
				line = Console.ReadLine();
				if (line != null)
				{
					rp.Run(line);

					CategoryCounts = new Dictionary<string, int>() {{"Character", 0},
																													{"OrdinaryCharacter", 0},
																													{"Grouping", 0},
																													{"Quantifier", 0},
																													{"Assertion", 0},
																													{"Alternation", 0},
																													{"Backreference", 0},
																													{"Comment", 0},
																													{"Invalid", 0}};
					WriteColoredRegularExpression(rp.FlattenedTokens);
					Console.WriteLine();
					Console.WriteLine();

					foreach (var c in CategoryCounts)
					{
						if (c.Value > 0)
						{
							Console.ForegroundColor = ConsoleColor.White;
							Console.Write('\t');
							Console.Write(c.Value);

							Console.ForegroundColor = ConsoleColor.Gray;
							Console.Write('\t');
							Console.Write(c.Key);

							Console.WriteLine();
						}
					}
					Console.ResetColor();

					Console.WriteLine(new string('-', 40));
				}
				Console.WriteLine();
				Console.WriteLine();
			}
			while (line != null);

		}


		static void WriteColoredRegularExpression(List<RegexToken> Tokens)
		{
			foreach(var Token in Tokens)
			{
				switch (Token.Category)
				{
					case RegexToken.Categories.Character :
						Console.ForegroundColor = ConsoleColor.Yellow;
						CategoryCounts["Character"]++;
						break;
					case RegexToken.Categories.OrdinaryCharacter :
						Console.ForegroundColor = ConsoleColor.White;
						CategoryCounts["OrdinaryCharacter"]++;
						break;
					case RegexToken.Categories.Grouping :
						Console.ForegroundColor = ConsoleColor.Green;
						CategoryCounts["Grouping"]++;
						break;
					case RegexToken.Categories.Quantifier:
						Console.ForegroundColor = ConsoleColor.Cyan;
						CategoryCounts["Quantifier"]++;
						break;
					case RegexToken.Categories.Assertion:
						Console.ForegroundColor = ConsoleColor.Magenta;
						CategoryCounts["Assertion"]++;
						break;
					case RegexToken.Categories.Alternation:
						Console.ForegroundColor = ConsoleColor.Magenta;
						CategoryCounts["Alternation"]++;
						break;
					case RegexToken.Categories.Backreference:
						Console.ForegroundColor = ConsoleColor.Magenta;
						CategoryCounts["Backreference"]++;
						break;
					case RegexToken.Categories.Comment:
						Console.ForegroundColor = ConsoleColor.Gray;
						CategoryCounts["Comment"]++;
						break;
					case RegexToken.Categories.Invalid:
						Console.ForegroundColor = ConsoleColor.Red;
						CategoryCounts["Invalid"]++;
						break;
				}
				Console.Write(Token.Pattern);
				Console.ResetColor();
			}
			
		}

	}
}
